package net.zoneland.knowledge.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;

import net.zoneland.knowledge.config.EsConfig;
import net.zoneland.knowledge.constant.Constants;
import net.zoneland.knowledge.enums.DictParentEnum;
import net.zoneland.knowledge.model.DictItem;
import net.zoneland.knowledge.model.EsQuestion;
import net.zoneland.knowledge.model.QaQueryDto;
import net.zoneland.knowledge.model.QaResponse;
import net.zoneland.knowledge.model.SubjectLevel;
import net.zoneland.knowledge.service.ApiService;
import net.zoneland.knowledge.service.DictItemService;
import net.zoneland.knowledge.service.EsService;
import net.zoneland.knowledge.service.QaBankService;
import net.zoneland.knowledge.service.QaQueryService;
import net.zoneland.knowledge.service.SubjectLevelService;
import net.zoneland.knowledge.service.impl.search.SearchDto;
import net.zoneland.knowledge.service.impl.search.SearchOperationChain;
import net.zoneland.knowledge.service.impl.search.SearchResultOperationChain;
import net.zoneland.knowledge.utils.ElasticSearchPoolUtil;
import net.zoneland.knowledge.utils.ResponseUtils;

/**
 * .
 *
 * @author: bcc
 * 2021/5/25
 */
@Service
public class QaQueryServiceImpl implements QaQueryService {

    @Autowired
    private SearchOperationChain searchOperationChain;

    /**
     * 查询结果处理链.
     */
    @Autowired
    private SearchResultOperationChain searchResultOperationChain;

    @Autowired
    private ApiService apiService;

    @Autowired
    private QaBankService qaBankService;

    @Autowired
    private EsService esService;

    @Autowired
    private DictItemService dictItemService;
    
    @Autowired
    private SubjectLevelService subjectLevelService;

    @Override
    public SearchDto queryById(final QaQueryDto qaQueryDto) throws Exception {
        RestHighLevelClient client = ElasticSearchPoolUtil.getClient();
        final SearchDto searchDto = new SearchDto();
        searchDto.setQaQueryDto(qaQueryDto);
        searchDto.generateAnserId();
        QaResponse qaResponse;

        try {
            EsQuestion esQuestion = esService.getById(qaQueryDto.getId());
            if (null != esQuestion) {
                qaBankService.loadMoreInfoFromDb(esQuestion, qaQueryDto.getVisitType());
                final ArrayList<EsQuestion> esQuestions = Lists.newArrayList(esQuestion);
                searchDto.setEsQuestions(esQuestions);
                // 过滤相关数据(权限、数据过滤等)
                searchResultOperationChain.searchOrDeal(searchDto);
                setRobotName(searchDto.getEsQuestions(), qaQueryDto);
                qaResponse = ResponseUtils.assembleResponse(esQuestion, qaQueryDto);
            } else {
                final String noAnswer = dictItemService.findDictByParentId(DictParentEnum.NO_ANSWER_REPLY.getValue()).stream().
                    filter(dictItem -> Constants.NO_ANSWER_KEY_ANSWER.equals(dictItem.getDictValue())).map(
                    DictItem::getDictName).findFirst().orElse(null);
                qaResponse = ResponseUtils.generateNoAnswer(qaQueryDto.getRobotName(), noAnswer);
            }
            searchDto.setQaResponse(qaResponse);
        } finally {
            ElasticSearchPoolUtil.returnClient(client);
        }
        return searchDto;
    }

    @Override
    public SearchDto search(final QaQueryDto qaQueryDto) throws Exception {
        final SearchDto searchDto = new SearchDto();
        searchDto.setQaQueryDto(qaQueryDto);
        searchDto.generateAnserId();
        searchOperationChain.searchOrDeal(searchDto);
        return searchDto;
    }

    /**
     * 通过路径查询.
     * @param qaQueryDto 查询参数
     * @return 查询结果
     * @throws Exception 异常
     */
    @Override
    public SearchDto queryByPath(final QaQueryDto qaQueryDto) throws Exception {

        final List<EsQuestion> result = esService.queryByPath(qaQueryDto);
        final SearchDto searchDto = new SearchDto();
        searchDto.generateAnserId();
        searchDto.setQaQueryDto(qaQueryDto);
        searchDto.setEsQuestions(result);
        searchDto.setStopSearch(true);
        // 过滤相关数据(权限、数据过滤等)
        searchResultOperationChain.searchOrDeal(searchDto);
        if (CollectionUtils.isNotEmpty(result)) {
            if (result.size() == 1) {
                EsQuestion esQuestion = result.get(0);
                qaBankService.loadMoreInfoFromDb(esQuestion, qaQueryDto.getVisitType());
                searchDto.setEsQuestions(result);
                QaResponse qaResponse = ResponseUtils.assembleResponse(esQuestion, qaQueryDto);
                searchDto.setQaResponse(qaResponse);
                return searchDto;
            }
            searchDto.setQaResponse(searchDto.getQaResponse());
            return searchDto;
        }
        final String noAnswer = dictItemService.findDictByParentId(DictParentEnum.NO_ANSWER_REPLY.getValue()).stream().
            filter(dictItem -> Constants.NO_ANSWER_KEY_ANSWER.equals(dictItem.getDictValue())).map(
            DictItem::getDictName).findFirst().orElse(null);
        QaResponse qaResponse = ResponseUtils.generateNoAnswer(qaQueryDto.getRobotName(), noAnswer);
        searchDto.setQaResponse(qaResponse);
        return searchDto;
    }
    
    @Override
    public void setRobotName(final List<EsQuestion> esQuestions, final QaQueryDto qaQueryDto) throws Exception {
        boolean hasDeptQa = esQuestions.stream().anyMatch(item -> StringUtils.isNotBlank(item.getOrgDeptDn()));
        String deptRobotName = null;
        if (hasDeptQa) {
            deptRobotName = apiService.getRobotInfo(qaQueryDto.getLoginUserPojo(), false).getRobotName();
        }
        for (EsQuestion esQuestion : esQuestions) {
            if (StringUtils.isNotBlank(esQuestion.getOrgDeptDn())) {
                esQuestion.setRobotName(deptRobotName);
            } else {
                esQuestion.setRobotName(qaQueryDto.getRobotName());
            }
        }
    }

    @Override
    public SearchDto queryByPathCombineConfig(final QaQueryDto qaQueryDto) throws Exception {

        final List<SubjectLevel> subjectLevels = subjectLevelService.queryByPath(qaQueryDto);
        final List<EsQuestion> rsFromSubjects = subjectLevels.stream()
            .map(item -> {
                EsQuestion esQuestion = new EsQuestion();
                esQuestion.setCategory(item.getCategory());
                esQuestion.setSubject(true);
                esQuestion.setLevel1Title(qaQueryDto.getLevel1Title());
                if (StringUtils.isBlank(qaQueryDto.getLevel2Title())) {
                    esQuestion.setLevel2Title(item.getSubjectName());
                } else {
                    esQuestion.setLevel2Title(qaQueryDto.getLevel2Title());
                    esQuestion.setLevel3Title(item.getSubjectName());
                }
                return esQuestion;
            })
            .collect(Collectors.toList());
        final List<EsQuestion> result = esService.queryByPathOnlyQuestion(qaQueryDto);
        List<EsQuestion> resultCombineAll = new ArrayList<>();
        // 返回结果科目在前
        resultCombineAll.addAll(rsFromSubjects);
        resultCombineAll.addAll(result);
        final SearchDto searchDto = new SearchDto();
        searchDto.generateAnserId();
        searchDto.setQaQueryDto(qaQueryDto);
        searchDto.setEsQuestions(resultCombineAll);
        searchDto.setStopSearch(true);
        // 过滤相关数据(权限、数据过滤等)
        searchResultOperationChain.searchOrDeal(searchDto);
        if (CollectionUtils.isNotEmpty(resultCombineAll)) {
            if (CollectionUtils.isEmpty(rsFromSubjects) && resultCombineAll.size() == 1) {
                EsQuestion esQuestion = resultCombineAll.get(0);
                qaBankService.loadMoreInfoFromDb(esQuestion, qaQueryDto.getVisitType());
                searchDto.setEsQuestions(resultCombineAll);
                QaResponse qaResponse = ResponseUtils.assembleResponse(esQuestion, qaQueryDto);
                searchDto.setQaResponse(qaResponse);
                return searchDto;
            }
            searchDto.setQaResponse(searchDto.getQaResponse());
            return searchDto;
        }
        final String noAnswer = dictItemService.findDictByParentId(DictParentEnum.NO_ANSWER_REPLY.getValue()).stream().
            filter(dictItem -> Constants.NO_ANSWER_KEY_ANSWER.equals(dictItem.getDictValue())).map(
            DictItem::getDictName).findFirst().orElse(null);
        QaResponse qaResponse = ResponseUtils.generateNoAnswer(qaQueryDto.getRobotName(), noAnswer);
        searchDto.setQaResponse(qaResponse);
        return searchDto;
    }

}
